package dao

import (
	"encoding/json"
	"fmt"
	"git.huoys.com/middle-end/kratos/pkg/naming/kubernetes"
	core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
	endpoint "github.com/envoyproxy/go-control-plane/envoy/api/v2/endpoint"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"sync"
)

var (
	kubernetesNamespaceFile = "/var/run/secrets/kubernetes.io/serviceaccount/namespace"
	defaultNamespace        = "default"
	k8s                     *K8S
	lock                    sync.RWMutex
	EndpointMap             map[string][]*endpoint.Endpoint
)

type EndpointsList struct {
	ApiVersion string
	Kind string
	Items []*kubernetes.Endpoints
	Metadata ListMeta
}

type ListMeta struct {
	Continue string
	RemainingItemCount int64
	ResourceVersion string
	SelfLink string
}

type K8S struct {
	k8sClient kubernetes.K8sClient
}

func NewK8sClient() (*K8S, error){

	if k8s == nil {
		k8sClient, err := kubernetes.NewInClusterK8sClient()
		if err != nil {
			log.Printf("[NewK8sClient] error : %s", err.Error())
			return nil, err
		}
		k8s = &K8S{k8sClient: k8sClient}
	}
	EndpointMap = make(map[string][]*endpoint.Endpoint)
	k8s.InitEndpoints()
	return k8s, nil
}

func (k *K8S) ListK8SEndpoints() (*EndpointsList, error){
	u, err := url.Parse(fmt.Sprintf("%s/api/v1/namespaces/%s/endpoints",
		k.k8sClient.Host(), getCurrentNamespaceOrDefault()))
	if err != nil {
		return &EndpointsList{}, err
	}
	req, err := k.k8sClient.GetRequest(u.String())
	if err != nil {
		return &EndpointsList{}, err
	}
	resp, err := k.k8sClient.Do(req)
	if err != nil {
		return &EndpointsList{}, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return &EndpointsList{}, fmt.Errorf("invalid response code %d", resp.StatusCode)
	}
	result := &EndpointsList{}
	err = json.NewDecoder(resp.Body).Decode(result)
	log.Printf("[ListK8SEndpoints] result %v", result.Items)
	return result, err
}

func (k *K8S)InitEndpoints() error {
	list, err := k.ListK8SEndpoints()
	if err != nil {
		log.Println("ListK8SEndpoints error... ", err.Error())
		return err
	}
	for _, e := range list.Items {
		name := e.Metadata.Name
		log.Printf("[InitEndpoints] Name %s", name)

		EndpointMap[name] = []*endpoint.Endpoint{}
		for _, subset := range e.Subsets {
			log.Printf("[InitEndpoints] Addresses %s", subset.Addresses)
			log.Printf("[InitEndpoints] Ports: %v", subset.Ports)
			port := 8000
			for _, p := range subset.Ports {
				if p.Name == "http" {
					port = p.Port
				}
			}
			for _, addr := range subset.Addresses {

				ep := &endpoint.Endpoint{
					Address:              &core.Address{
						Address: &core.Address_SocketAddress{
							SocketAddress: &core.SocketAddress{
								Protocol:             core.SocketAddress_TCP,
								Address:              addr.IP,
								PortSpecifier:        &core.SocketAddress_PortValue{PortValue: uint32(port)},
							},
						},
					},
				}
				EndpointMap[name] = append(EndpointMap[name], ep)
				log.Println("append....")
			}
		}
		log.Printf("[InitEndpoints] %s : %v", name, EndpointMap[name])
	}
	return nil
}

func getCurrentNamespaceOrDefault() string {
	ns, err := ioutil.ReadFile(kubernetesNamespaceFile)
	if err != nil {
		return defaultNamespace
	}
	return string(ns)
}
